﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace BOW
{
   public class Calculator
    {
        double k1 = 1.2;
        double b = 0.5;
        Dictionary<string, int> dic = new Dictionary<string, int>();

        Common commo = new Common();
        //tính trọng số từ ti đối với 1 bug report BRj -- ct3
        public double calculation_wi(double idf_ti, double tf_ti_BRj, double BRj_length, double dl_avg)
        {
            double wi = (idf_ti * tf_ti_BRj * (k1 + 1)) / (tf_ti_BRj + k1 * (1 - b + b * (BRj_length / dl_avg)));
            return wi;
        }

        //tính tần số từ ti xuất hiện trong 1 bug report BRj
        public double calculation_tf_ti_BRj(double f_ti, double max_f)
        {
            return 0.5 + (0.5 * f_ti / max_f);
            //return f_ti / max_f;
            //return 1 + Math.Log10(f_ti);
            //return k1 + (1 - k1) * f_ti / max_f;
        }

        //tính tần số nghịch đảo của từ ti -- ct4
        public double calculation_idf_ti(int N, double df_ti)
        {
            return Math.Log10((double.Parse(N.ToString()) - df_ti + 0.5) / (df_ti + 0.5));
        }

        //tính dl_avg
        public double calculation_dl_avg(int BR_length, int N)
        {
            return BR_length / N;
        }

        public Dictionary<string, int> GetTf_qi(List<string> tempBug)
        {
            Dictionary<string, int> result = new Dictionary<string, int>();
            foreach (string s1 in tempBug)
            {
                string s = s1.ToUpper();
                if (result.ContainsKey(s))
                {
                    int val = int.Parse(result[s].ToString());
                    result.Remove(s);
                    result.Add(s, ++val);
                    result[s] = result[s]++;
                }
                else
                    result.Add(s, 1);
            }
            return result;
        }

        public Dictionary<string, double> Create_Vecto(string bug)
        {
            Dictionary<string, double> BOW = new Dictionary<string, double>();
            List<string> listCurrentBug = new List<string>(); // danh sách chứa bug nhập vô.
            listCurrentBug = commo.processWordofBug(bug); // xử lý từ
            Dictionary<string, int> dic_bug = new Dictionary<string, int>(); //tu dien chua cac tu va so lan xuat hien cua no trong 1 bug
            dic_bug = GetTf_qi(listCurrentBug); // từ điển chứa từ và số lần xuất hiện của từ trong bug mới nhập  
            
            Dictionary<string, double> vecto = new Dictionary<string, double>();
            BOW = commo.ReadBagOfWord();
            foreach (string item in dic_bug.Keys) {
                foreach (string s in BOW.Keys)
                {
                    if (item==s) {
                        vecto.Add(item, double.Parse(BOW[s].ToString()));
                    }
                }
            }  
            return vecto;  // vecto trong so
        }

       //So sanh vector
        public bool Compare_Vecto(Dictionary<string, double> X, Dictionary<string, double> Y, double threshold)
        {
            double tongbp_X = 0; // bình phương độ dài vecto X
            double tongbp_Y = 0; // bình phương độ dài vecto Y
            double tich = 0; //tích vô hướng 2 vecto
            double cos = 0; // góc giữa 2 vecto
            List<string> same = new List<string>(); // chứa những phần tử trùng nhau của X và Y
            List<double> X_val = new List<double>();
            List<double> Y_val = new List<double>();
            foreach (string x in X.Keys)
            {
                foreach (string y in Y.Keys)
                {
                    if (y == x)
                    {
                        same.Add(x);
                        break;
                    }
                }
            }  
            if (same.Count >=1)
            {
                X = Sort(X, same);
                Y = Sort(Y, same);
                
                foreach (string item in X.Keys)
                {
                    X_val.Add(double.Parse(X[item].ToString()));
                }
                foreach (string item in Y.Keys)
                {
                    Y_val.Add(double.Parse(Y[item].ToString()));
                }

                if (X.Count > Y.Count) //nếu số phần tử X nhiều hơn Y thì tính tích vô hướng đến phần tử cuối của Y và ngược lại 
                {
                    for (int i = 0; i < Y.Count; i++)
                    {
                        tich += X_val[i] * Y_val[i];
                    }
                }
                else
                {
                    for (int i = 0; i < X.Count - 1; i++)
                    {
                        tich += X_val[i] * Y_val[i];
                    }
                }

                for (int i = 0; i < X.Count - 1; i++)
                {
                    tongbp_X += X_val[i] * X_val[i];
                }
                for (int i = 0; i < Y.Count - 1; i++)
                {
                    tongbp_Y += Y_val[i] * Y_val[i];
                }
                cos = tich / (Math.Sqrt(tongbp_X) * Math.Sqrt(tongbp_Y)); // hệ số góc giữa 2 vecto X Y
            }
            // MessageBox.Show(cos.ToString());
            if (cos > threshold)  // nếu cos lớn hơn ngưỡng cho phép thì là trùng lặp
                return false;
            return true;
        }

        // Tinh Score(q,d)
        public Dictionary<string, double> Score(string q, DataTable dt,Dictionary<string,double> BOW,List<string> Str, int N, double d_avg)
        {
            string temp_CurrentBug = "";
            List<string> listCurrentBug = new List<string>(); // danh sách chứa bug nhập vô.

            temp_CurrentBug = commo.RemoveDuplicateWords(q);//xu ly tu trung lap
            listCurrentBug = commo.processWordofBug(temp_CurrentBug); // xử lý từ
            Dictionary<string, int> dic_bug = new Dictionary<string, int>(); //tu dien chua cac tu va so lan xuat hien cua no trong 1 bug
            dic_bug = GetTf_qi(listCurrentBug); // từ điển chứa từ và số lần xuất hiện của từ trong bug mới nhập      

            //tinh tan suat xuat hien cua tu ti trong toan bug report
            int df_ti = 0; // số bug report có chứa từ item trong toàn bộ bug đã có
            Dictionary<string, int> GetTf_d = new Dictionary<string, int>();
            Dictionary<string, double> ListResult = new Dictionary<string, double>();
            List<string> temp_bug = new List<string>();
            List<string> temp_Remobug = new List<string>();
            string temp_Rebug = "";
            int tf_qi = 0;//int.Parse(dic_bug[item].ToString());

            #region Tính Score
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                string d = "";
                foreach (string t in Str)
                {
                    d += dt.Rows[i][t].ToString();
                }
                int d_length = 0;
                temp_bug = commo.processWordofBug(d);
                temp_Rebug = commo.RemoveDuplicateWords(d);
                temp_Remobug = commo.processWordofBug(temp_Rebug);
                // xem trong bug đang xét từ t xuất hiện bao nhiêu lần trong tập bug.(tính |d|)
                foreach (string t in temp_Remobug)
                {
                    if (BOW.ContainsKey(t.ToUpper()))
                        d_length++;
                }
                GetTf_d = GetTf_qi(temp_bug);// từ điển chứa từ và số lần xuất hiện của từ trong bug hiện hành
                double score = 0;
                foreach (string ite in temp_Remobug)
                {
                    foreach (string item in dic_bug.Keys)
                    {
                        if (ite.ToUpper() == item.ToUpper())
                        {
                            df_ti = 0;
                            //Xác định từ chứa trong bao nhiêu bug
                            for (int j = 0; j < dt.Rows.Count; j++)
                            {
                                string s = "";
                                foreach (string t in Str)
                                {
                                    s += dt.Rows[j][t].ToString();
                                }
                                if (s.ToUpper().IndexOf(item.ToUpper()) != -1) //có từ item trong câu s
                                    df_ti++;
                            }
                            tf_qi = int.Parse(GetTf_d[item].ToString()); //số lần xuất hiện của từ item trong toàn bộ bug report
                            double idf_qi = calculation_idf_ti(N, double.Parse(df_ti.ToString())); //tính idf (qi)
                            score += calculation_wi(idf_qi, tf_qi, d_length, d_avg); // tính wi dựa vào công thức 4                       
                        }
                    }
                }
                ListResult.Add(d, score);
            }
            #endregion

            return ListResult;
            // show ket qua

        }

       private Dictionary<string,double> Sort(Dictionary<string,double> a, List<string>b ){
           Dictionary<string, double> temp = new Dictionary<string, double>();
           foreach (string i in a.Keys) {
               foreach (string j in b) {
                   if (j == i) { 
                        temp.Add(i,double.Parse(a[i].ToString()));
                        break;
                   }
               }
           }
           foreach(string i in a.Keys){
               bool check = true;
               foreach (string j in temp.Keys) {
                   if (j == i) {
                       check = false;
                      break;
                   }
               }
               if (check == true) {
                   temp.Add(i, double.Parse(a[i].ToString()));
               }
           }
           return temp;
       }

        
    }
}
